---
title: "Module 10: Common Pitfalls"
description: "From a JavaScript developer's perspective, this module analyzes common conceptual pitfalls and error-prone points in Python."
---

## 1. Introduction

When you switch from one language to another, the trickiest parts are often not the new syntax, but the "gotchas" that seem similar but behave completely differently. These subtle differences can lead to hard-to-detect bugs and confusion.

This module is specifically designed for you—a developer transitioning from JavaScript to Python—to sort out some of the most common conceptual pitfalls.

> 💡 **Learning Strategy**: Don't just memorize. Understand the "why" behind each pitfall and compare it to JavaScript's behavior. This way, you will naturally avoid them in your actual coding.

## 2. Truthy vs. Falsy

In Python, empty collection types (like lists, dictionaries, tuples) are considered "falsy." This is a significant difference from JavaScript's behavior, where an empty array `[]` and an empty object `{}` are both "truthy."

<PythonEditor title="Truthy vs. Falsy Comparison" compare={true}>
```javascript !! js
// JavaScript
if ([]) {
  console.log("Empty array is truthy in JS"); // This will be printed
}

if ({}) {
  console.log("Empty object is truthy in JS"); // This will be printed
}

if ("") {
  console.log("Empty string is falsy"); // This will not be printed
}

if (0) {
  console.log("0 is falsy"); // This will not be printed
}
```

```python !! py
# Python
if []:
    print("Empty list is Falsy in Python")  # This will not be printed
else:
    print("Empty list is falsy")

if {}:
    print("Empty dictionary is Falsy in Python")  # This will not be printed
else:
    print("Empty dictionary is falsy")

if "":
    print("Empty string is Falsy")  # This will not be printed
else:
    print("Empty string is falsy")

if 0:
    print("0 is Falsy")  # This will not be printed
else:
    print("0 is falsy")
```
</PythonEditor>

## 3. `this` vs. `self`

In JavaScript class methods, `this` is a keyword whose value is determined when the function is called. In Python instance methods, the first parameter (named `self` by convention) explicitly represents the instance itself, and it is not a keyword.

<PythonEditor title="this vs. self Comparison" compare={true}>
```javascript !! js
// JavaScript
class Counter {
  constructor() {
    this.count = 0;
  }

  increment() {
    this.count++;
    console.log(this.count);
  }
}

const counter = new Counter();
counter.increment(); // 1
```

```python !! py
# Python
class Counter:
    def __init__(self):
        self.count = 0

    def increment(self):  # `self` must be explicitly passed as the first parameter
        self.count += 1
        print(self.count)

counter = Counter()
counter.increment()  # 1
```
</PythonEditor>

## 4. Variable Scope

JavaScript (ES6+) has block-level scope (defined by `{}`), while Python's scope is based on functions (or classes, modules). Variables defined in code blocks like `for` loops will "leak" into the outer scope in Python.

<PythonEditor title="Scope Comparison" compare={true}>
```javascript !! js
// JavaScript (Block Scope)
for (let i = 0; i < 3; i++) {
  console.log(i);
}
// console.log(i); // ReferenceError: i is not defined

if (true) {
  const blockVar = 'hello';
}
// console.log(blockVar); // ReferenceError: blockVar is not defined
```

```python !! py
# Python (Function Scope)
for i in range(3):
    print(i)

print(f"After the loop, i still exists: {i}") # Output: After the loop, i still exists: 2

if True:
    block_var = 'hello'

print(f"After the if block, the variable still exists: {block_var}") # Output: After the if block, the variable still exists: hello
```
</PythonEditor>

## 5. Mutable Default Arguments

This is a very classic and notorious "gotcha" in Python. If a function's default argument is a mutable object (like a list or dictionary), that object will be shared across all calls. This is completely different from JavaScript's behavior.

<PythonEditor title="Mutable Default Argument Comparison" compare={true}>
```javascript !! js
// JavaScript
function append(item, arr = []) {
  arr.push(item);
  return arr;
}

console.log(append(1)); // [1]
console.log(append(2)); // [2] (A new empty array is created for each call)
```

```python !! py
# Python (The wrong way)
def append_bad(item, arr=[]):
    arr.append(item)
    return arr

print(append_bad(1))  # [1]
print(append_bad(2))  # [1, 2] (The list is shared across all calls!)

# The correct way
def append_good(item, arr=None):
    if arr is None:
        arr = []
    arr.append(item)
    return arr

print(append_good(1)) # [1]
print(append_good(2)) # [2]
```
</PythonEditor>

## 6. `null`/`undefined` vs. `None`

JavaScript has two values to represent "nothing": `null` (representing an "intentionally set empty value") and `undefined` (representing "not defined"). In Python, there is only one corresponding concept: `None`.

<PythonEditor title="null/undefined vs. None" compare={true}>
```javascript !! js
// JavaScript
let a; // undefined
let b = null; // null

function greet(name) {
  // If no argument is passed, name is undefined
  console.log(name);
}
```

```python !! py
# Python
a = None  # Only None

def greet(name=None):
    # Usually use None as the default value
    print(name)

# Check if it is None
if a is None:
    print("a is None")
```
</PythonEditor>

## 7. Summary

Understanding and mastering these differences will help you write robust, unsurprising Python code more quickly. When you encounter unexpected behavior, it's a good idea to come back to this list and check if you've fallen into one of these "traps."
